package cacheBreakdown;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 防止缓存击穿的代码写法
 *
 * @Author: ShenWei
 * @Date: 2024/09/06/11:19
 */
@Slf4j
@Component
public class GetValue {

    @Resource
    private JedisPool jedisPool;

    @Resource
    private DataBaseTest dataBaseTest;

    private static final String LUA = "return redis.call('SET', KEYS[1], ARGV[1], 'EX', ARGV[2], 'NX')";

    private static final Long EXPIRE_TIME = 300L;

    private String getValue(String key) {
        Jedis jedis = null;
        String value = null;

        try {
            jedis = jedisPool.getResource();
            value = jedis.get(key);
            // 如果查询结果为空 - 缓存过期
            if (StrUtil.isBlank(value)) {
                // 注意这里加入一个互斥操作,使用了NX参数,确保只有一个线程进入数据库查询,将查询结果放回缓存
                if("OK".equals(jedis.eval(LUA, Collections.singletonList("key_mutext"), Arrays.asList("1", "180")))) {
                    value = dataBaseTest.get(key);
                    jedis.setex(key, EXPIRE_TIME, value);
                    jedis.del("key_mutext");
                } else {
                    // 等待进入数据库查询的线程将数据放入缓存 - 50ms
                    Thread.sleep(50);
                    // 再次从缓存取数据
                    value = jedis.get(key);
                }
            }
        } catch (Exception e) {
            log.info("查询异常!");
        }
        return value;
    }
}
